作者:心叶
时间:2019-07-18 10:34
本文章构思的实现方法在github上有对应的项目已经实现,项目依旧在不断改进中:watcher.js
核心方法说明
Object.defineProperty(obj,key,{
get(){
// todo1
},
set(newValue){
// todo2
}
});
比如obj是一个json,其有一个值key,也就是obj.key。我们可以通过上面的方法对设置和获取obj.key的时候进行拦截处理,而这就是js部分双向绑定的核心。
设计思路
页面 → JS
监听输入框的输入时间,如果有输入,就主动改变js中的值,这样,页面到js这一条路就通了。
JS → 页面
js部分通过前面说的Object.defineProperty方法,对需要双向绑定的数据进行拦截,发现数据改变的时候,就主动去修改页面显示,这样,js到页面这一条路就通了。
难点
上面的说明看起来很简单,然而,事实并非如此,主要有下面几个问题(其实主要是设计的问题):
- js数据改变了,你怎么知道应该修改页面中哪些地方?
- 页面的表达式可能很复杂,如何解析
- 数组或对象如何监听
实现
主体对象
控制整个流程,余下的都是由这里协调资源。
let iCrush = function (options) {
// 管理的数据(双向绑定)
this._data = options.data || {};
// 对维护的数据进行监听
this.__observe();
// 获取挂载点
this.$el = $$(options.el)[0];
// 编译结点
this.__compile();
}
数据拦截者observe.js
对象options的data中定义的key的编辑会在这里拦截,通知专门处理变化情况的(同步视图和数据)。
export default function(){
for (let key in this._data) {
// 定义拦截钩子
Object.defineProperty(this._data, key, {
get() {
// todo
},
set(newValue) {
// todo
}
});
};
编译程序compile.js
简单点说,就是分析结点中的内容,有没有定义的指令等,根据结点内容追加需要管理的东西。
export default function(){
let nodes = this.$el.childNodes;
for (let i = 0; i < nodes.length; i++) {
// 如果不是文本结点,继续编译
if (node.nodeType !== 3) {
// todo
}
// 开始正式解析一个结点(分为文本结点和非文本结点)
// 解析的意思就是标记需要管理的属性,文本等
if (node.nodeType === 3) {
// 如果是文本
} else {
// 如果不是文本
}
}
};
后记
上面力求简单,具体的代码没有显示出来,如果需要看具体代码,请去github/iCrush上查看。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。